#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <cassert>
#include <cstdlib>
#include <pthread.h>

// .hpp  声明和实现都在这里   
// header only 开源代码


class Thread;// 声明
class Context
{
public:
    Context()
        : _this(nullptr)
        , _args(nullptr)
    {}
    ~Context()
    {
        // do nothing
    }
public:
    Thread* _this;
    void* _args;
};

class Thread
{
private:
    typedef std::function<void* (void*)> func_t;// 或可使用模板，此处为了使其简单，使用void*作为参数类型
    const int size = 1024;
public:
    Thread(func_t func, void* args, const int number)
        : _func(func)
        , _args(args)
    {
        // c++
        // _tname = "thread->";
        // _tname += std::to_string(number);

        // 这里使用C语言的接口，是为了增强C接口的使用熟练度，以应对将来可能经常面对的系统编程和网络编程，因为他们提供的接口大多都是C接口
        char buffer[size];
        snprintf(buffer, sizeof(buffer) - 1, "thread-%d", number);
        _tname = buffer;

        // 启动线程
        start();
    }



    // 线程等待
    void join()
    {
        int n = pthread_join(_tid, nullptr);
        assert(n == 0);// assert: debug发布的时候存在，release发布时不存在，此时n就是一个被定义但没有被使用的变量，
        // 这样在有的编译器下会报warning
        (void)n;// 这个行为就是告诉编译器，变量n被使用，不要报warning
    }

    ~Thread()
    {
        // do nothinf
    }
private:
    // void* start_routine(void* args)// 类内成员，还有this指针作为参数
    static void* start_routine(void* args)
    {
        // return _func(args);// static函数只能调用static成员
        Context* ctx = static_cast<Context*>(args);
        void* ret = ctx->_this->run(ctx->_args);// or:
        // return ctx->_this->_func(ctx->_args);
        delete ctx;

        return ret;
    }
    void* run(void* args)
    {
        return _func(args);
    }
    // 线程启动
    void start()
    {
        Context* ctx = new Context();
        ctx->_this = this;
        ctx->_args = _args;

        // int n = pthread_create(&_tid, nullptr, _func, _args);// 此函数是C函数，但function是C++的接口，C语言不识别
        int n = pthread_create(&_tid, nullptr, start_routine, ctx);// 从这里看出start_routine有且只有一个参数，并接收_args作为参数
        assert(n == 0);// 保证线程创建成功
        /*
        意料之外：使用异常或if
        意料之种：使用assert
        */
        (void)n;
    }
private:
    pthread_t _tid;// 线程id
    std::string _tname;// 线程名字
    func_t _func;// 线程执行的函数
    void* _args;// 线程执行的参数
};
